package com.open.center.common.util;

import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import org.springframework.util.StringUtils;

import com.open.center.common.constant.OpenConstant;

/**
 * Json工具类
 *
 * @author Riche's
 * @since 2025/5/23
 */
@Slf4j
public class JSON {

    private static final ObjectMapper MAPPER = new ObjectMapper();

    static {
        //ALWAYS - 默认策略，任何情况都执行序列化
        //NON_NULL - 非空  属性为NULL 不序列化
        //NON_ABSENT - null的不会序列化，但如果类型是AtomicReference，依然会被序列化
        //NON_EMPTY - null、集合数组等没有内容、空字符串等，都不会被序列化
        //NON_DEFAULT - 如果字段是默认值，就不会被序列化
        //CUSTOM - 此时要指定valueFilter属性，该属性对应一个类，用来自定义判断被JsonInclude修饰的字段是否序列化
        //USE_DEFAULTS - 当JsonInclude在类和属性上都有时，优先使用属性上的注解，此时如果在序列化的get方法上使用了JsonInclude，并设置为USE_DEFAULTS，就会使用类注解的设置
        MAPPER.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        MAPPER.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        // 忽略没有定义的字段
        MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        MAPPER.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
        MAPPER.setDateFormat(new SimpleDateFormat(OpenConstant.DATE_TIME_FORMAT));
        MAPPER.setTimeZone(TimeZone.getDefault());

        JavaTimeModule javaTimeModule = new JavaTimeModule();
        javaTimeModule.addSerializer(LocalDateTime.class,
                new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(OpenConstant.DATE_TIME_FORMAT)));
        javaTimeModule.addDeserializer(LocalDateTime.class,
                new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(OpenConstant.DATE_TIME_FORMAT)));
        javaTimeModule.addSerializer(LocalDate.class,
                new LocalDateSerializer(DateTimeFormatter.ofPattern(OpenConstant.DATE_FORMAT)));
        javaTimeModule.addDeserializer(LocalDate.class,
                new LocalDateDeserializer(DateTimeFormatter.ofPattern(OpenConstant.DATE_FORMAT)));
        javaTimeModule.addSerializer(LocalTime.class,
                new LocalTimeSerializer(DateTimeFormatter.ofPattern(OpenConstant.TIME_FORMAT)));
        javaTimeModule.addDeserializer(LocalTime.class,
                new LocalTimeDeserializer(DateTimeFormatter.ofPattern(OpenConstant.TIME_FORMAT)));
        MAPPER.registerModule(javaTimeModule)
                .registerModule(javaTimeModule)
                .registerModule(new ParameterNamesModule());

    }

    /**
     * JSON字符串转为对象
     */
    @SneakyThrows
    public static <T> T toBean(String json, Class<T> clazz) {
        if (StringUtils.hasText(json)) {
            return MAPPER.readValue(json, clazz);
        }
        return null;
    }

    @SneakyThrows
    public static <T> T toBean(Object object, Class<T> clazz) {
        return MAPPER.convertValue(object, clazz);
    }

    @SneakyThrows
    public static <T> T toBean(Object object, TypeReference<T> reference) {
        return MAPPER.convertValue(object, reference);
    }

    @SneakyThrows
    public static <T> T toBean(String json, TypeReference<T> reference) {
        return MAPPER.readValue(json, reference);
    }

    @SneakyThrows
    public static <T> T toBean(String json, Class<?> parametrized, Class<?>... parameterClasses) {
        return MAPPER.readValue(json, parametricType(parametrized, parameterClasses));
    }

    @SneakyThrows
    public static <T> T toBean(String json, JavaType type) {
        return MAPPER.readValue(json, type);
    }

    /**
     * 构建泛型的JavaType
     *
     * @param parametrized     被泛型类，Bean<T>： Bean就是被泛型的类
     * @param parameterClasses 泛型的类，按照声明顺序。如：Bean<T1,T2>，按照T1,T2的顺序
     * @return Java类型
     */
    public static JavaType parametricType(Class<?> parametrized, Class<?>... parameterClasses) {
        return MAPPER.getTypeFactory().constructParametricType(parametrized, parameterClasses);
    }


    /**
     * 对象转为JSON字符串
     */
    @SneakyThrows
    public static String toJson(Object object) {
        if (object == null) {
            return null;
        }
        return MAPPER.writeValueAsString(object);
    }


    /**
     * 将JSON字符串数组转为List
     */
    @SneakyThrows
    public static <T> List<T> toList(String json, Class<T> parameterClasses) {
        return MAPPER.readValue(json, parametricType(ArrayList.class, parameterClasses));
    }

    @SneakyThrows
    public static Map<String, Object> toMap(String json) {
        if (!StringUtils.hasText(json)) {
            return Map.of();
        }
        TypeReference<HashMap<String, Object>> typeRef = new TypeReference<>() {
        };
        return MAPPER.readValue(json, typeRef);
    }

    /**
     * 对象转换
     *
     * @param source 原对象
     * @param target 目标对象
     * @param <T>    target type
     * @return target
     */
    @SneakyThrows
    public <T> T convert(Object source, Class<T> target) {
        if (source == null) {
            return null;
        }
        return MAPPER.readValue(toJson(source), target);
    }


    /**
     * 对象转为JsonNode
     */
    @SneakyThrows
    public static JsonNode toNode(Object object) {
        return MAPPER.convertValue(object, JsonNode.class);
    }

    /**
     * Json转为JsonNode
     */
    @SneakyThrows
    public static JsonNode toNode(String json) {
        return MAPPER.readTree(json);
    }

}
